from plyny.workstreams import Manager
from plyny.plio.files import File, TemporaryDirectory
from core.type_checking import verify_type
from util.args import Parser

import inspect


def wsname(value):
    return ':'.join(value.split('.')[:-1])


def parse_func(func):
    module = func_name = None

    for item in inspect.getmembers(func):
        if item[0] == '__module__':
            module = item[1]
        if item[0] == 'func_name':
            func_name = item[1]

    if module == '__main__':
        import __main__
        module = __main__.__file__.replace('.py', '').replace('/', '.')

    if not (module and func_name):
        raise ValueError('func')

    args = inspect.getargspec(func).args
    return module, func_name, args


class Event(object):
    def __init__(self, runner, open_manager, create_manager, instances=1,
            **kw):

        module, func_name, args = parse_func(runner)
        print module, func_name, args

        parser = Parser()

        parser.add_option('runner', required=True)
        parser.add_directory('open_manager', required=True)
        parser.add_directory('create_manager', required=True)
        parser.add_option('outputname', required=True)
        parser.add_option('inputstream', required=True)
        parser.add_int('index', required=True)
        parser.add_int('outof', required=True)

        self.runner = module + '.' + func_name
        self.parser = parser
        if isinstance(open_manager, Manager):
            open_manager = open_manager._dir
        if isinstance(create_manager, Manager):
            create_manager = create_manager._dir

        self.open_manager = open_manager
        self.create_manager = create_manager
        outputname = wsname(self.runner)
        self.outputname = outputname
        self.func_args = args
        self.kw = kw
        self.instances = instances
        self.cl = self.command_line()

    def command_line(self):
        vals = {}
        copy = self.kw.copy()
        for item in self.func_args:
            if item not in ('manager', 'inputstream'):
                vals[item] = copy[item]
                del copy[item]

        if copy:
            raise TypeError('%s not in %s' % (copy.keys()[0], self.runner))
        return vals


def _exec(values):
    main_func = values[0]
    parser_name = values[1]
    args = values[2:]

    import subprocess
    from subprocess import PIPE
#    print 'python %s %s %s' % (main_func, parser_name, ' '.join(args))
    try:
        subprocess.check_call('python %s %s %s' % (main_func, parser_name, 
            ' '.join(args)), shell=True)
    except subprocess.CalledProcessError as e:
        print e
        print 'HEEEEEE'
        assert False
        sys.exit(1)

        
class Flow(object):
    def __init__(self):
        self.events = []

    def add_event(self, event):
        verify_type(event, Event, 'event')
        self.events.append(event)

    def run(self, inputstream):
        from multiprocessing import Pool
        import cPickle

        for i, event in enumerate(self.events):
#            print inputstream
            with TemporaryDirectory() as t:
                args = event.cl
                pline = []
                for key, value in args.iteritems():
                    pline.append('--%s %s' % (key, value))
                    if isinstance(value, int):
                        event.parser.add_int(key)
                    else:
                        event.parser.add_option(key)

                args = ' '.join(pline)

                filename = (t.path() / 'main.py')
                from plyny.workstreams.flow import main
                File(filename).write(inspect.getsource(main))

                parser_name = (t.path() / 'parser').real()
                cPickle.dump(event.parser, open(parser_name, 'w'))
#                print event.instances, len(inputstream)
                event.instances = min(event.instances, len(inputstream))
                pl = Pool(event.instances)
                values = []
                for j in xrange(event.instances):
                    cl = (' --index %d --outof %d --outputname %s --open_manager %s --create_manager %s --runner %s --inputstream %s %s' %
                                (j,
                                 event.instances,
                                 event.outputname,
                                 event.open_manager,
                                 event.create_manager,
                                 event.runner,
                                 inputstream,
                                 args
                                 )
                        )
#                    print cl
                    values.append((filename, parser_name, cl))

                pl.map(_exec, values)
                inputstream = wsname(event.runner)

        
if __name__ == '__main__':
    from dbg.m import run
    from dbg.m2 import run2
    from dbg.m3 import run3
    f = Flow()
    f.add_event(Event(run, 'wss', 'wss', instances=2, depth=2))
    f.add_event(Event(run2, 'wss', 'wss', instances=1))
    try:
        f.add_event(Event(run3, 'wss', 'wss', instances=2, depth=2))
    except TypeError:
        pass

    f.add_event(Event(run3, 'wss', 'wss', instances=4))
#    f.add_event(Event(run, 'wss', instances=2, depth=2))
    f.run('mk')
